import importlib

from ctaf_core.ctaf_objects.base_exception import CTAFbaseException
from ctaf_core.ctaf_objects.base_ctaf_service import BaseCTAFservice
from typing import Any, Dict

from ctaf_core.log_trace_bundle.logging import LogRecorder, LoggerFactory
from ctaf_facade.enumerations.error_code_enum import ErrorCodeEnum


class BusServiceContainer:
    log_recorder: LogRecorder = LoggerFactory.get_logger()

    #key:value of rpc_sevice_register_settings is "rpcServiceInfo":{"rpcServiceName01": {"servicePath": "rpcService01", "methodName": "serviceMethod01"},...}
    def __init__(self, rpc_sevice_register_settings: Dict[str, Dict[str, str]]):

        #key:value of this Dict is rpc_service_instance_name:rpc_service_instance
        self.__rpc_service_instances: Dict[str, BaseCTAFservice] = {}

        #key:value of this Dict is rpc_service_name:rpc_service_instance_name.service_method_name
        self.__registered_rpc_services: Dict[str, str] = {}

        self.register_rpc_services_from_settings(rpc_sevice_register_settings)


    def add_service_instance(self, instance_name: str, rpc_service_instance: BaseCTAFservice):
        self.__rpc_service_instances[instance_name] = rpc_service_instance


    def register_rpc_service(self, rpc_service_name: str, rpc_service_class_path: str, rpc_service_method_name: str):
        module_name, class_name = rpc_service_class_path.rsplit('.', 1)
        module = importlib.import_module(module_name)
        rpc_service_class = getattr(module, class_name)
        rpc_service_instance = rpc_service_class()
        self.add_service_instance(rpc_service_class_path, rpc_service_instance)
        self.__registered_rpc_services[rpc_service_name] = rpc_service_class_path + "." + rpc_service_method_name
        BusServiceContainer.log_recorder.write_info_log(rpc_service_name + " has been registered: " + self.__registered_rpc_services[rpc_service_name])

    def invoke_rpc_sevice(self, rpc_service_name: str, *args, **kwargs)-> Any:
        if  rpc_service_name in self.__registered_rpc_services.keys():
            rpc_service_method_path = self.__registered_rpc_services[rpc_service_name]
            rpc_service_class_path, rpc_service_method_name = rpc_service_method_path.rsplit('.', 1)
            rpc_service_instance = self.__rpc_service_instances[rpc_service_class_path]
            if not rpc_service_instance:
                raise CTAFbaseException(ErrorCodeEnum.NO_TARGET_SERVICE)
            if hasattr(rpc_service_instance, rpc_service_method_name):
                rpc_service_method = getattr(rpc_service_instance, rpc_service_method_name)
                return rpc_service_method(*args, **kwargs)
            else:
                raise CTAFbaseException(ErrorCodeEnum.NO_TARGET_SERVICE)
        else:
            raise CTAFbaseException(ErrorCodeEnum.NO_TARGET_SERVICE)

    def register_rpc_services_from_settings(self, rpc_sevice_register_settings: Dict[str, Dict[str, str]]):
        for rpc_service_name in rpc_sevice_register_settings.keys():
            rpc_service_class_path = rpc_sevice_register_settings[rpc_service_name]["servicePath"]
            rpc_service_method_name = rpc_sevice_register_settings[rpc_service_name]["methodName"]
            self.register_rpc_service(rpc_service_name,rpc_service_class_path, rpc_service_method_name)

class BusServiceContainerFactory:
    __bus_service_container = None

    @staticmethod
    def get_bus_service_container(rpc_sevice_register_settings: Dict[str, Dict[str, str]]) -> BusServiceContainer:
        if BusServiceContainerFactory.__bus_service_container is None:
            BusServiceContainerFactory.__bus_service_container = BusServiceContainer(rpc_sevice_register_settings)
        return BusServiceContainerFactory.__bus_service_container

